/* CPU control.
 * (C) 2001, 2002, 2003, 2004 Rusty Russell
 *
 * This code is licenced under the GPL.
 */
#include <seminix/types.h>
#include <seminix/cpumask.h>
#include <seminix/cpu.h>
#include <seminix/cache.h>
#include <seminix/init.h>
#include <seminix/param.h>
#include <seminix/slab.h>

struct cpumask __cpu_possible_mask __read_mostly;
struct cpumask __cpu_online_mask __read_mostly;

/*
 * cpu_bit_bitmap[] is a special, "compressed" data structure that
 * represents all NR_CPUS bits binary values of 1<<nr.
 *
 * It is used by cpumask_of() to get a constant address to a CPU
 * mask value that has a single bit set only.
 */

/* cpu_bit_bitmap[0] is empty - so we can back into it */
#define MASK_DECLARE_1(x)	[x + 1][0] = (1UL << (x))
#define MASK_DECLARE_2(x)	MASK_DECLARE_1(x), MASK_DECLARE_1(x + 1)
#define MASK_DECLARE_4(x)	MASK_DECLARE_2(x), MASK_DECLARE_2(x + 2)
#define MASK_DECLARE_8(x)	MASK_DECLARE_4(x), MASK_DECLARE_4(x + 4)

const unsigned long cpu_bit_bitmap[BITS_PER_LONG + 1][BITS_TO_LONGS(CONFIG_NR_CPUS)] = {

	MASK_DECLARE_8(0),	MASK_DECLARE_8(8),
	MASK_DECLARE_8(16),	MASK_DECLARE_8(24),
#if BITS_PER_LONG > 32
	MASK_DECLARE_8(32),	MASK_DECLARE_8(40),
	MASK_DECLARE_8(48),	MASK_DECLARE_8(56),
#endif
};

const DECLARE_BITMAP(cpu_all_bits, CONFIG_NR_CPUS) = CPU_BITS_ALL;

static int __boot_cpu_id __ro_after_init;

int boot_cpu_id(void)
{
    return __boot_cpu_id;
}

void __init boot_cpu_init(void)
{
    cpumask_clear(&__cpu_possible_mask);
    cpumask_clear(&__cpu_online_mask);

    set_cpu_possible(0, true);
    set_cpu_online(0, true);

    __boot_cpu_id = 0;
}

struct cpuhp_setup {
    const char *name;
    int    (*startup)(int cpu);
};

static __initdata bool cpuhp_hp_initialized = false;
static __initdata struct cpuhp_setup cpuhp_hp_states[CPUHP_ONLINE];

int __init cpuhp_register_callback(int (*startup)(int cpu), const char *name, enum cpuhp_state state)
{
    struct cpuhp_setup *cpuhp;

    if (!cpuhp_hp_initialized) {
        memset(cpuhp_hp_states, 0, sizeof (struct cpuhp_setup) * CPUHP_ONLINE);
        cpuhp_hp_initialized = true;
    }

    if (!startup || !name)
        return -EINVAL;

    if (state <= CPUHP_OFFLINE || state >= CPUHP_ONLINE)
        return -EINVAL;

    cpuhp = &cpuhp_hp_states[state];
    if (cpuhp->startup)
        return -EEXIST;

    cpuhp->name = kstrdup(name, GFP_KERNEL);
    if (!cpuhp->name)
        goto out;

    cpuhp->startup = startup;

    return 0;
out:
    return -ENOMEM;
}

/**
 * notify_cpu_starting(cpu) - Invoke the callbacks on the starting CPU
 * @cpu: cpu that just started
 *
 * It must be called by the arch code on the new cpu, before the new cpu
 * enables interrupts and before the "boot" cpu returns from __cpu_up().
 */
void __init notify_cpu_starting(int cpu)
{
    int i;
    struct cpuhp_setup *cpuhp;

    for (i = 0; i < CPUHP_ONLINE; i++) {
        cpuhp = &cpuhp_hp_states[i];
        if (cpuhp->startup) {
            if (cpuhp->startup(cpu))
                pr_warn("Cpu%d starting %s Failed!\n", cpu, cpuhp->name);
        }
    }
}

static __init int cpuhp_register_finish(void)
{
    int i;
    struct cpuhp_setup *cpuhp;

    for (i = 0; i < CPUHP_ONLINE; i++) {
        cpuhp = &cpuhp_hp_states[i];
        if (cpuhp->name)
            kfree(cpuhp->name);
    }

    return 0;
}
core_initcall(cpuhp_register_finish)
